﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CodeGenerator
{
    class BaseDwarfParser
    {
        protected bool HasErrors { get; private set; }
        protected Token currentToken;
        protected DwarfScanner scanner;
        protected AsTree tree;

        public event EventHandler<SimpleEventArgs> ParseError;

        public BaseDwarfParser()
        {
            HasErrors = false;
        }

        public AsTree GetTree()
        {
            return tree;
        }

        protected void Reset()
        {
            tree = new AsTree();
            HasErrors = false;
        }

        protected Token GetNextToken()
        {
            currentToken = scanner.GetNextToken();

            if (currentToken.Type == TokenType.COMMENT)
            {
                currentToken = GetNextToken();
            }

            Check(currentToken.Type != TokenType.ERROR);
            return currentToken;
        }

        protected void ParseToken(TokenType type)
        {
            Check(GetNextToken().Type == type);
        }

        protected void CheckNextTokenIs(TokenType type)
        {
            Check(GetForwardToken().Type == type);
        }

        protected Token GetForwardToken()
        {
            Token t = scanner.GetForwardToken();

            if (t.Type == TokenType.COMMENT)
            {
                currentToken = scanner.GetNextToken();
                t = GetForwardToken();
            }

            Check(t.Type != TokenType.ERROR);
            
            return t;
        }

        protected void Check(bool success)
        {
            if (!success)
            {
                TriggerError();
            }
        }

        protected void TriggerError(string additionalText = "")
        {
            HasErrors = true;
            EventHandler<SimpleEventArgs> handler = ParseError;

            if (handler != null)
            {
                additionalText = (additionalText.Length > 0) ? additionalText + " " : additionalText;
                handler(this, new SimpleEventArgs(GetErrorText() + additionalText));
            }
        }

        protected string GetErrorText()
        {
            if (currentToken.Type == TokenType.ERROR)
            {
                return currentToken.Attribute;
            }

            return "Unexpected token at " + 
                   scanner.GetCurrentPositionAsString() +
                   " " + currentToken.Attribute + "(" + currentToken.Type + ")";
        }
    }
}
